﻿using System.Diagnostics;
using System.Threading;

namespace System
{
    ///<summary>Цыклы алгоритмы</summary>
    public static class Cycle
    {
        ///// <summary>Циклическое выполнение действия в параллельном режиме</summary>
        ///// <param name="cycle">Выполняемое действие</param><param name="N">Число повторений</param>
        //[Diagnostics.DebuggerStepThrough]
        //public static void ForParallel(this Action<int, int> cycle, int N) { ForParallel(cycle, N, true); }

        [DebuggerStepThrough]
        public static void ForParallel(this Action<int> cycle, int N, bool Whait = true)
        {
            ((Action<int, int>)((i, n) => cycle(i))).ForParallel(N, Whait);
        }

        [DebuggerStepThrough]
        public static void ForLinear(this Action<int> cycle, int N) { ((Action<int, int>)((i, n) => cycle(i))).ForLinear(N); }

        /// <summary>Циклическое выполнение действия в параллельном режиме</summary>
        /// <param name="cycle">Выполняемое действие</param>
        /// <param name="N">Число повторений</param>
        /// <param name="Whait">Оиждать давершения цикла?</param>
        [DebuggerStepThrough]
        public static void ForParallel(this Action<int, int> cycle, int N, bool Whait = true)
        {
            if(Whait)
            {
                var whait = new ManualResetEvent[N];
                for(var i = 0; i < N; i++)
                {
                    var local_i = i;
                    var w = whait[i] = new ManualResetEvent(false);
                    ThreadPool.QueueUserWorkItem(o => { cycle(local_i, N); w.Set(); });
                }
                whait.Foreach(w => w.WaitOne());
            }
            else
                for(var i = 0; i < N; i++)
                {
                    var local_i = i;
                    ThreadPool.QueueUserWorkItem(o => cycle(local_i, N));
                }
        }

        /// <summary>Циклическое выполнение действия в последовательном режиме</summary>
        /// <param name="cycle">Выполняемое действие</param><param name="N">Число повторений</param>
        public static void ForLinear(this Action<int, int> cycle, int N) { for(var i = 0; i < N; i++) cycle(i, N); }

        public static void WhileDo(this Action cycle, Func<bool> WhilePredicate) { while(WhilePredicate()) cycle(); }
        public static void WhileDo(this Action<int> cycle, Func<bool> WhilePredicate) { for(var i = 0; WhilePredicate(); i++) cycle(i); }
        public static void WhileDo(this Action<int> cycle, Func<int, bool> WhilePredicate) { for(var i = 0; WhilePredicate(i); i++) cycle(i); }

        public static void DoWhile(this Action cycle, Func<bool> WhilePredicate) { do { cycle(); } while(WhilePredicate()); }
        public static void DoWhile(this Action<int> cycle, Func<bool> WhilePredicate) { var i = 0; do { cycle(i++); } while(WhilePredicate()); }
        public static void DoWhile(this Action<int> cycle, Func<int, bool> WhilePredicate) { var i = 0; do { cycle(i++); } while(WhilePredicate(i)); }
    }
}
